﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Engine;
using Game.NetWork;
using Game.NetWork.Packages;
using GameEntitySystem;
using TemplatesDatabase;

namespace Game
{
    public class SubsystemNaturallyBuildings : Subsystem
    {
        public static Dictionary<string, Dictionary<Point2, Dictionary<Point3, int>>> Buildings = new Dictionary<string, Dictionary<Point2, Dictionary<Point3, int>>>();

        public SubsystemTerrain SubsystemTerrain;

        public List<BuildingInfo> BuildingInfos = new List<BuildingInfo>();

        public List<AreaInfo> AreaInfos = new List<AreaInfo>();

        public SubsystemFurnitureBlockBehavior m_SubsystemFurnitureBlockBehavior;

        public override void Load(ValuesDictionary valuesDictionary)
        {
            SubsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>();
            BuildingInfos.Add(new BuildingInfo("House/Supercity", (192, 192), 0, (3072, 66, 3072), 550, 550));
            BuildingInfos.Add(new BuildingInfo("House/血泪", (64, 64), 0, (1024, 66, 1024), 550, 550));
            try
            {
                string value = valuesDictionary.GetValue<string>("OriginatePoints");
                string[] array = value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string text in array)
                {
                    int index = int.Parse(text.Split('@')[0]);
                    string[] array2 = text.Split('@')[1].Split(',');
                    BuildingInfos[index].OriginatePoint = new Point3(int.Parse(array2[0]), int.Parse(array2[1]), int.Parse(array2[2]));
                }
            }
            catch (Exception ex)
            {
                Log.Warning("SubsystemNaturallyBuildings-Load:" + ex.Message);
            }

            try
            {
                string value2 = valuesDictionary.GetValue<string>("AreaOriginatePoints");
                string[] array3 = value2.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string text2 in array3)
                {
                    int index2 = int.Parse(text2.Split('@')[0]);
                    string[] array4 = text2.Split('@')[1].Split(',');
                    AreaInfos[index2].OriginatePoint = new Point3(int.Parse(array4[0]), int.Parse(array4[1]), int.Parse(array4[2]));
                }
            }
            catch (Exception ex2)
            {
                Log.Warning("SubsystemNaturallyBuildings-Load:" + ex2.Message);
            }

            m_SubsystemFurnitureBlockBehavior = base.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>();
            if (m_SubsystemFurnitureBlockBehavior != null)
            {
                Log.Information($"加载家具包");
            }
        }

        public override void Save(ValuesDictionary valuesDictionary)
        {
            int num = 0;
            string text = "";
            string text2 = "";
            foreach (BuildingInfo buildingInfo in BuildingInfos)
            {
                if (buildingInfo.OriginatePoint.HasValue)
                {
                    text = text + num + "@" + buildingInfo.OriginatePoint.Value.ToString() + ";";
                }

                num++;
            }

            valuesDictionary.SetValue("OriginatePoints", text);
            foreach (AreaInfo areaInfo in AreaInfos)
            {
                if (areaInfo.OriginatePoint.HasValue)
                {
                    text2 = text2 + num + "@" + areaInfo.OriginatePoint.Value.ToString() + ";";
                }

                num++;
            }

            valuesDictionary.SetValue("AreaOriginatePoints", text2);
        }

        public static void Initialize()
        {
            LoadBuilding("House/Supercity");
            LoadBuilding("House/血泪");
        }

        public static List<FurnitureDesign> LoadFurniturePack(SubsystemTerrain subsystemTerrain, string name)
        {
            XElement overridesNode = ContentManager.Get<XElement>(name);
            ValuesDictionary valuesDictionary = new ValuesDictionary();
            valuesDictionary.ApplyOverrides(overridesNode);
            return SubsystemFurnitureBlockBehavior.LoadFurnitureDesigns(subsystemTerrain, valuesDictionary);
        }

        public static void InitFurnitureDesign(SubsystemFurnitureBlockBehavior furnitureBlockBehavior, ComponentFurnitureInventory componentFurnitureInventory)
        {
            int num = 0;
            int num2 = 0;
            string text = "House/家具包1";
            List<List<FurnitureDesign>> list = FurnitureDesign.ListChains(LoadFurniturePack(furnitureBlockBehavior.SubsystemTerrain, text));
            List<FurnitureDesign> list2 = new List<FurnitureDesign>();
            furnitureBlockBehavior.GarbageCollectDesigns();
            foreach (List<FurnitureDesign> item in list)
            {
                FurnitureDesign furnitureDesign = furnitureBlockBehavior.TryAddDesignChain(item[0], garbageCollectIfNeeded: false);
                if (furnitureDesign == item[0])
                {
                    list2.Add(furnitureDesign);
                }
                else if (furnitureDesign == null)
                {
                    num2++;
                }
                else
                {
                    num++;
                }
            }

            if (list2.Count <= 0)
            {
                return;
            }

            FurnitureSet furnitureSet = furnitureBlockBehavior.NewFurnitureSet("FC家具包", text);
            if (CommonLib.WorkType == WorkType.Server)
            {
                CommonLib.Net.QueuePackage(new FurniturePackage(furnitureSet));
            }

            foreach (FurnitureDesign item2 in list2)
            {
                furnitureBlockBehavior.AddToFurnitureSet(item2, furnitureSet);
                if (CommonLib.WorkType == WorkType.Server)
                {
                    CommonLib.Net.QueuePackage(new FurniturePackage(item2, furnitureSet));
                }
            }

            componentFurnitureInventory.FurnitureSet = furnitureSet;
        }

        public static float ChangeMountainRangeFactor(float x, float z, float factor, SubsystemNaturallyBuildings SNBuildings)
        {
            foreach (BuildingInfo buildingInfo in SNBuildings.BuildingInfos)
            {
                if (buildingInfo.CalculatPlainRange(new Point2((int)(x / 16f), (int)(z / 16f))))
                {
                    float num = Vector2.Distance(new Vector2(x, z), new Vector2(buildingInfo.AreaCenterPoint));
                    float x2 = num / buildingInfo.Radius;
                    factor *= MathUtils.Clamp(x2, 0f, 1f);
                    return factor;
                }
            }

            return factor;
        }

        public static void GenerateBuildingPrepare(TerrainChunk chunk, SubsystemNaturallyBuildings SNBuildings)
        {
            if (SNBuildings == null)
            {
                return;
            }

            foreach (BuildingInfo buildingInfo in SNBuildings.BuildingInfos)
            {
                if (!buildingInfo.CalculatPlainRange(chunk.Coords))
                {
                    continue;
                }

                for (int i = 0; i < 16; i++)
                {
                    for (int j = 0; j < 16; j++)
                    {
                        int num = chunk.Origin.X + i - buildingInfo.AreaCenterPoint.X;
                        int num2 = chunk.Origin.Y + j - buildingInfo.AreaCenterPoint.Y;
                        int num3 = (int)buildingInfo.Radius;
                        if (num * num + num2 * num2 >= num3 * num3)
                        {
                            continue;
                        }

                        if (!buildingInfo.OriginatePoint.HasValue)
                        {
                            for (int num4 = 254; num4 > 0; num4--)
                            {
                                if (chunk.GetCellContentsFast(3, num4, 3) != 0)
                                {
                                    buildingInfo.OriginatePoint = new Point3(buildingInfo.OriginateCoord.X * 16, num4, buildingInfo.OriginateCoord.Y * 16);
                                    break;
                                }
                            }
                        }

                        int num5 = buildingInfo.OriginatePoint.Value.Y;
                        int num6 = 0;
                        for (int num7 = 254; num7 > 0; num7--)
                        {
                            num6 = chunk.GetCellContentsFast(i, num7, j);
                            if (num6 != 0)
                            {
                                num5 = num7;
                                break;
                            }
                        }

                        if (num5 > buildingInfo.OriginatePoint.Value.Y)
                        {
                            for (int num8 = num5; num8 > buildingInfo.OriginatePoint.Value.Y; num8--)
                            {
                                chunk.SetCellValueFast(i, num8, j, 0);
                            }
                        }
                        else
                        {
                            if (num5 >= buildingInfo.OriginatePoint.Value.Y)
                            {
                                continue;
                            }

                            if (num6 == 3 || num6 == 4 || num6 == 2 || num6 == 8 || num6 == 6 || num6 == 7)
                            {
                                for (int k = num5; k <= buildingInfo.OriginatePoint.Value.Y; k++)
                                {
                                    chunk.SetCellValueFast(i, k, j, num6);
                                }
                            }
                            else
                            {
                                for (int l = num5; l <= buildingInfo.OriginatePoint.Value.Y; l++)
                                {
                                    chunk.SetCellValueFast(i, l, j, 8);
                                }
                            }
                        }
                    }
                }
            }
        }

        public static void GenerateBuilding(TerrainChunk chunk, SubsystemNaturallyBuildings FCBuildings)
        {
            if (FCBuildings == null)
            {
                return;
            }

            foreach (BuildingInfo buildingInfo in FCBuildings.BuildingInfos)
            {
                if (buildingInfo.OriginatePoint.HasValue)
                {
                    Point3 originatePoint = buildingInfo.OriginatePoint.Value - new Point3(0, buildingInfo.HightShiftCount, 0);
                    GenerateBuildings(buildingInfo, originatePoint, chunk);
                }
            }
        }

        public static void GenerateArea(TerrainChunk chunk, SubsystemNaturallyBuildings FCBuildings)
        {
            if (FCBuildings == null)
            {
                return;
            }

            foreach (AreaInfo areaInfo in FCBuildings.AreaInfos)
            {
                if (areaInfo.OriginatePoint.HasValue)
                {
                    Point3 originatePoint = areaInfo.OriginatePoint.Value - new Point3(0, areaInfo.HightShiftCount, 0);
                    GenerateAreas(areaInfo, originatePoint, chunk);
                }
            }
        }

        public static void GenerateAreas(AreaInfo areaInfo, Point3 originatePoint, TerrainChunk chunk)
        {
            int num = chunk.Coords.X - originatePoint.X / 16;
            int num2 = chunk.Coords.Y - originatePoint.Z / 16;
            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    for (int k = originatePoint.Y + areaInfo.HightShiftCount + 1; k < 254; k++)
                    {
                        chunk.SetCellValueFast(i, k, j, 0);
                    }
                }
            }
        }

        public Point2 GetRandomPoint(int seed, List<BuildingInfo> buildingInfos)
        {
            int count = buildingInfos.Count;
            Point2 point = new Point2(-1000, -1000);
            Random random = new Random(seed + count * 3);
            if (count == 0)
            {
                point = new Point2(random.Int(0, 50), random.Int(0, 50));
            }
            else
            {
                int num = 0;
                int num2 = 0;
                int num3 = 0;
                bool flag;
                do
                {
                    flag = true;
                    num++;
                    num2 = random.Int(-50, 50);
                    num3 = random.Int(-50, 50);
                    foreach (BuildingInfo buildingInfo in buildingInfos)
                    {
                        if (MathUtils.Abs(buildingInfo.OriginateCoord.X - num2) < 50 && MathUtils.Abs(buildingInfo.OriginateCoord.Y - num3) < 50)
                        {
                            flag = false;
                            break;
                        }
                    }
                }
                while (!flag && num < 10000);
                point = new Point2(num2, num3);
            }

            string locationName;
            switch (count)
            {
                case 2:
                    locationName = "小镇";
                    break;
                case 1:
                    locationName = "天空城";
                    break;
                case 0:
                    locationName = "悦灵城";
                    break;
                default:
                    locationName = "";
                    break;
            }

            string logMessage = string.Format("{0}坐标：[x:{1},y:?,z:{2}]", locationName, point.X * 16, point.Y * 16);
            Log.Warning(logMessage);

            return point;

        }

        public static void GenerateBuildings(BuildingInfo buildingInfo, Point3 originatePoint, TerrainChunk chunk)
        {
            int x = chunk.Coords.X - originatePoint.X / 16;
            int y = chunk.Coords.Y - originatePoint.Z / 16;
            if (!Buildings[buildingInfo.Name].TryGetValue(new Point2(x, y), out var value))
            {
                return;
            }

            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    for (int k = originatePoint.Y + buildingInfo.HightShiftCount + 1; k < 254; k++)
                    {
                        chunk.SetCellValueFast(i, k, j, 0);
                    }
                }
            }

            foreach (Point3 key in value.Keys)
            {
                int value2 = value[key];
                if (key.Y <= buildingInfo.HightShiftCount && Terrain.ExtractContents(value2) == 15)
                {
                    value2 = 0;
                }

                chunk.SetCellValueFast(key.X, key.Y + originatePoint.Y, key.Z, value2);
            }
        }

        public static void LoadBuilding(string name)
        {
            int num = 0;
            try
            {
                Log.Information("加载了1");
                string text = ContentManager.Get<string>(name).Replace("\r", string.Empty);
                string[] array = text.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                text = string.Empty;
                Log.Information("加载了2");
                string[] array2 = array;
                foreach (string text2 in array2)
                {
                    num++;
                    string[] array3 = text2.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (array3.Length > 3)
                    {
                        int num2 = int.Parse(array3[0]);
                        int y = int.Parse(array3[1]);
                        int num3 = int.Parse(array3[2]);
                        int value = int.Parse(array3[3]);
                        Point2 key = new Point2(num2 / 16, num3 / 16);
                        Point3 key2 = new Point3(num2 % 16, y, num3 % 16);
                        if (!Buildings.ContainsKey(name))
                        {
                            Buildings[name] = new Dictionary<Point2, Dictionary<Point3, int>>();
                        }

                        if (!Buildings[name].ContainsKey(key))
                        {
                            Buildings[name][key] = new Dictionary<Point3, int>();
                        }

                        Buildings[name][key][key2] = value;
                    }
                }

                Log.Information("加载了2");
            }
            catch (Exception ex)
            {
                if (Buildings.ContainsKey(name))
                {
                    Buildings.Remove(name);
                }

                Log.Warning($"LoadBuilding-{name}-Line-{num}:{ex.Message}");
            }
        }
    }
}